//File		: FCExportImport3D.cpp
//Purpose	: Implementation class for Export/Import Collada to 3DCoat
//Data		: 18/07/2009
//---------------------------------------------------------------------
#include "stdafx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDMaterial.h"
#include "FCDocument/FCDAsset.h"
#include "FCDocument/FCDLibrary.h"
#include "FCDocument/FCDGeometry.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDGeometryPolygonsTools.h"
#include "FCDocument/FCDGeometryPolygonsInput.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FCDocument/FCDExtra.h"
#include "FUtils/FUFileManager.h"
#include "FUtils/FUTestBed.h"
#include "FUtils/FULogFile.h"
#include "FUtils/FUDaeEnum.h"
#include "FCExportImport3D.h"
#include "FCExportImportUtils.h"
#include "FCMeshConvertUtils.h"

namespace comms { 
FCExportImport3D::FCExportImport3D(const char* file)
{
	m_file = file;
	m_document = NULL;
	m_logFile = new FULogFile("LogFile.txt");
	
}
FCExportImport3D::~FCExportImport3D()
{
	SAFE_DELETE(m_document);
	SAFE_DELETE(m_logFile);
}
//EncodeObj(export) mesh object to collada file format
int FCExportImport3D::EncodeObj(const cMeshConatainer& Mesh)
{
	int ret = 0;
	//Load document in FCDocument class 
	SAFE_DELETE(m_document);
	m_document = FCollada::NewDocument();
	//Filling Collada Document
	FillColladaDocument(Mesh);
	//Save collada
	FCollada::SaveDocument(m_document, m_file);
	return ret;
}
/*
	int idCurMtl = 0;
    int CurObject=-1;
	uni_hash<DWORD,hVec3,800000,8192> PosHash;
	cList<DWORD> PosID;
	cStr MaterialFileName;
	int pp=0;
	{
		// Get Vertext Positions
		cVec3 Position;
		Position.x=atof(m_Tokens[1]);
		Position.y=atof(m_Tokens[2]);
		Position.z=atof(m_Tokens[3]);
		hVec3 v2(Position.x,Position.y,Position.z);
		DWORD* id=PosHash.get(v2);
		if(id==NULL){				
			DWORD p=Mesh.GetPositions().Add(Position);
			PosID.Add(p);
			PosHash.add(v2,p);								
		}else {
			PosID.Add(*id);
		}			
		// Get TexCoords
		cVec2 TexCoord;
		TexCoord.x=atof(m_Tokens[1]);
		TexCoord.y=atof(m_Tokens[2]);
		Mesh.GetTexCoords().Add(TexCoord);
		// Get Normals
		cVec3 Normal;
		Normal.x=atof(m_Tokens[1]);
		Normal.y=atof(m_Tokens[2]);
		Normal.z=atof(m_Tokens[3]);			
		Mesh.GetNormals().Add(Normal);
		// Get Faces
		// if faceCount > 1	{
				if(CurObject==-1) {
					cObject obj;
					CurObject=0;
					Mesh.GetObjects().Add(obj);
					Mesh.GetObjects().GetLast().Name="default";
				}
				if(!AddFace(Mesh, idCurMtl, CurObject)) {
					return false;
				}
			}
		// Get Material
			if(m_Tokens.Count() > 1) { // There is a name token.
				// If raw is empty, usemtl was listed before any faces.
				// So previous default material is not needed at all.
			
					bool IsFound = false;
					for(int idMtl = 0; idMtl < Mesh.GetMaterials().Count(); idMtl++) {
						if(cStr::Equals(Mesh.GetMaterials()[idMtl].Name, m_Tokens[1])) {
							IsFound = true;
							idCurMtl = idMtl;
							break;
						}
					}
					if(!IsFound) 
					{
						char TexName[_MAX_PATH]="";
					//	GetTextureFromMtl(Src.GetFilePn(),MaterialFileName,m_Tokens[1],TexName,true);										idCurMtl = Mesh.GetMaterials().Count();
                        cSurface m;
						Mesh.GetMaterials().Add(m);
						Mesh.GetMaterials().GetLast().Name = m_Tokens[1];
						Mesh.GetMaterials().GetLast().Tex[0].FileName=TexName;
					}
				}
		// Get Tangents
		cVec<cVec3, 2> tangents;
		//...
		Mesh.GetTangents().Add(tangents);
		//Get UVSet
		cUVSet uvset;
		//...
		Mesh.GetUVSets().Add(uvset);
	   //Get VMaps
		cVMapElm vmap;
		//...
		Mesh.GetVMaps().Add(vmap);
		//Get VMTypes
		cVMapType vmtype;	
	    //...
		Mesh.GetVMTypes().Add(vmtype);
		}
	}
    // Default material:
	cList<cVec3i>& raw=Mesh.GetRaw();
	for(int i=0;i<raw.Count();i++){
		int n=raw[i][0];
		int j;
		for(j=0;j<n;j++){
			raw[i+j+1][0]=PosID[raw[i+j+1][0]];
		}
		i+=j;
	}
    if(Mesh.GetMaterials().Count()==0){
        cSurface m;
	    Mesh.GetMaterials().Add(m);
	    Mesh.GetMaterials().GetLast().Name = "default";
    }
	return true;
*/

// find index in current material
int FCExportImport3D::FindMaterialIDX(cMeshConatainer& Mesh, const char*material)
{
	int idCurMtl =-1;
	for(int idMtl = 0; idMtl < Mesh.GetMaterials().Count(); idMtl++) {
	if(cStr::Equals(Mesh.GetMaterials()[idMtl].Name, material)) {
		idCurMtl = idMtl;
		break;
		}
	}
	return idCurMtl;
}
bool FCExportImport3D::AddPolygons( FCDGeometryPolygons *polygons, 
									cMeshConatainer& Mesh, 
									int idCurMtl, 
									int CurObject) 
{
	FCDGeometryPolygonsInput* pV = polygons->FindInput(FUDaeGeometryInput::Semantic::POSITION);
	FCDGeometryPolygonsInput* pN = polygons->FindInput(FUDaeGeometryInput::Semantic::NORMAL);
	FCDGeometryPolygonsInput* pT = polygons->FindInput(FUDaeGeometryInput::Semantic::TEXCOORD);
	
	uint32* vList = (pV)?pV->GetIndices():0;	//vertices list
	uint32* nList = (pN)?pN->GetIndices():0;	//normal list
	uint32* tList = (pT)?pT->GetIndices():0;	//texture list
	size_t IndexCount = (pV)?pV->GetIndexCount():0;
	if(vList == 0)// || nList == 0 )//|| tList == 0)???
		return true;
	if (IndexCount > 0 && 
		IndexCount == pN->GetIndexCount())
	{
		Mesh.GetRaw().Add(comms::cVec3i(IndexCount,idCurMtl,CurObject));
		int texIndexCount = (pT)?pT->GetIndexCount():0;
		int normIndexCount = (pN)?pN->GetIndexCount():0;
		texIndexCount = (texIndexCount > IndexCount)?IndexCount:texIndexCount;
		normIndexCount= (normIndexCount > IndexCount)?IndexCount:normIndexCount;
		for(size_t i = 0; i < IndexCount; ++i) {
			comms::cVec3i index(vList[i],
								(i<normIndexCount)?nList[i]:-1,
								(i<texIndexCount)?tList[i]:-1);
			Mesh.GetRaw().Add(index);
		}
	}
	return true;
}

bool FCExportImport3D::FillMeshContainer(cMeshConatainer& Mesh )
{
	TEST_NAME(FillMeshContainer);
	FCDGeometryLibrary* library = m_document->GetGeometryLibrary();
	FCDMaterialLibrary* materialLibrary = m_document->GetMaterialLibrary();
	FCDGeometry* geometry = library->GetEntity(0);
	FailIf_L(geometry == NULL || !geometry->IsMesh(),m_logFile);
	FCDGeometryMesh* mesh = geometry->GetMesh();
	FailIf_L(mesh == NULL,m_logFile);
	
	//convert geometry source data 
	FCMeshConvertUtils::ConvertFCGSource2CoatSources(mesh,Mesh);
	FCMeshConvertUtils::ConvertFCTanBinorm2Coat(mesh, Mesh);
	
	//convert material library
	FCMeshConvertUtils::ConvertFCMaterialLib2CoatMaterial(materialLibrary,Mesh);
	
	size_t polyCount = mesh->GetPolygonsCount();
	int CurObject = -1;
	for(size_t j = 0; j < polyCount;j++) 
	{
		FCDGeometryPolygons *polygons = mesh->GetPolygons(j);
		if(CurObject==-1) {
			cObject obj;
			CurObject=0;
			Mesh.GetObjects().Add(obj);
			Mesh.GetObjects().GetLast().Name="default";
		}
		// find index in current material
		int idCurMtl = FindMaterialIDX(Mesh,polygons->GetMaterialSemantic());
		if(!AddPolygons(polygons, Mesh, idCurMtl, CurObject)) {
			return false;
		}
	}
	if(Mesh.GetMaterials().Count()==0){
        cSurface m;
	    Mesh.GetMaterials().Add(m);
	    Mesh.GetMaterials().GetLast().Name = "default";
    }
	return true;
}

bool FCExportImport3D::FillColladaDocument(const cMeshConatainer &Mesh)
{
	return true;

}
//DecodeObj(import) mesh container from collada file format
bool FCExportImport3D::DecodeObj(cMeshConatainer &Mesh)
{
	//Load document in FCDocument class 
	if(m_document==NULL) 
	{
		m_document = FCollada::NewDocument();
		bool isLoad = FCollada::LoadDocumentFromFile(m_document,m_file);
		if(isLoad){
			ProcessGeometryLibrary(m_document->GetGeometryLibrary()); //processing
		}
	}
	//Filling Mesh container
	return FillMeshContainer(Mesh);
}
void FCExportImport3D::ProcessGeometryLibrary(FCDGeometryLibrary* library)
{
	size_t geometryCount = library->GetEntityCount();
	for (size_t i = 0; i < geometryCount; ++i)
	{
		FCDGeometry* geometry = library->GetEntity(i);
		if (geometry->IsMesh())
		{
			ProcessMesh(geometry->GetMesh());
		}
	}
}

void FCExportImport3D::ProcessMesh(FCDGeometryMesh* mesh) 
{
	//FCDGeometryPolygonsTools::Triangulate(mesh);
	FCDGeometrySource* texcoordSource = mesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD);
	if (texcoordSource != NULL)
	{
		// Generate the texture tangents for this mesh' texcoords.
		FCDGeometryPolygonsTools::GenerateTextureTangentBasis(mesh, texcoordSource, true);
	}
//	FCDGeometryPolygonsTools::GenerateUniqueIndices(mesh);
//	FCDGeometryPolygonsTools::FitIndexBuffers(mesh, 1024*48); // 2 ^ 16 - 1: this	is a		hardware drawback.
}
};